package com.new1cloud.file.upload.client.bootstrap.handler;

import com.new1cloud.file.domain.ChunkFileUploadStatus;
import com.new1cloud.file.domain.FileChunkInfo;
import com.new1cloud.file.domain.FileUploadProgressStatus;
import com.new1cloud.file.domain.UploadProgressListener;
import com.new1cloud.file.tools.FileSlicerTool;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

import static com.new1cloud.file.upload.client.bootstrap.FileUploadClient.defaultChunkSize;

public class ChunkFileUploadStatusHandler extends ChannelInboundHandlerAdapter implements LocalCache {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    private final UploadProgressListener uploadProgressListener;

    public ChunkFileUploadStatusHandler(UploadProgressListener uploadProgressListener) {
        this.uploadProgressListener = uploadProgressListener;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ChunkFileUploadStatus) {
            log.info("客户端收到来自服务端的ChunkFileUploadStatus类型消息");
            ChunkFileUploadStatus chunkFileUploadStatus = (ChunkFileUploadStatus) msg;
            uploadProgressListener.progressChanged(FileUploadProgressStatus.builder().fileName(chunkFileUploadStatus.getFileName())
                    .transferPercentage(chunkFileUploadStatus.getUploadPercentage()).build());
            //表示上传失败，客户端进行重试上传该分片文件
            if(Objects.equals(0, chunkFileUploadStatus.getUploadStatus())) {
                log.warn("文件({})的分片文件({})上传失败,将重新上传.", chunkFileUploadStatus.getFileName(), chunkFileUploadStatus.getChunkName());
                FileChunkInfo chunkInfo = chunkFiles.get(chunkFileUploadStatus.getFileHash());
                if(Objects.isNull(chunkInfo)) {
                    log.error("未查询到文件({})的分片文件({})的相关信息，将停止上传该文件.", chunkFileUploadStatus.getFileName(), chunkFileUploadStatus.getChunkName());
                    return;
                }
                chunkInfo.getChunkFiles().stream()
                        .filter(cf -> Objects.equals(chunkFileUploadStatus.getChunkName(), cf.getChunkName()))
                        .findAny()
                        .ifPresent(chunkFile -> ctx.writeAndFlush(FileSlicerTool.gotChunkFileBytes(ctx,chunkInfo.getFilePath(),
                                chunkFile.getOffset(),
                                defaultChunkSize,
                                chunkFile)
                        ).addListener(future -> {
//                            boolean re = chunkFile.getChunkData().release();
                            log.info("文件({})的分片文件({})已上传，内存释放: {}", chunkFileUploadStatus.getFileName(), chunkFile.getChunkName(), true);
                        }));
                return;
            }
            //上传成功，则从chunkFiles里删除该chunkFile的信息
            log.info("文件({})的分片文件({})上传成功，将清除相关记录.", chunkFileUploadStatus.getFileName(), chunkFileUploadStatus.getChunkName());
            chunkFiles.remove(chunkFileUploadStatus.getFileHash());
        } else {
            log.error("客户端[ChunkFileUploadStatusHandler]收到非预期类型的消息:{},将被丢弃!", msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        log.error("客户端发生异常: ", cause);
        ctx.close();
    }
}
